/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * All Rights Researved.
 *
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
 *
 *  
 * @author: jin Chen
 * @date: Jun 15, 2003
 * @version: $VERSION$
 */
package edu.psu.geovista.app.plot.axis;

import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class XAxisOrder extends XAxis {
    //public static final float MAX_INITIAL_SIZE=200*30;// 
    //public static final int MIN_INTERVAL=20;
    public static final String PROPERTY_DEFAULT_INTERVAL="pdi";
    public final static int DEFAULT_INTERVAL=150;
    protected int maxInitSize;//=200*30;
    protected int minInterval;//=20;
    //
    protected int defaultInterval;//=150;//EFAULT_INTERVAL;
    /**
     *  
     * 0th element=0
     *  
     *  
     *  
     *  
     */
    protected ArrayList intervals;
    //protected int activeSize;

    /**
     *
     * @param numOfAxis   number of YAxis along this XAxis
     */
    public XAxisOrder(int numOfAxis){
        init();
        //this.setOrient(edu.psu.geovista.app.plot.ruler.Ruler.HORIZONTAL);
        this.numOfYAxis =numOfAxis;
        reset();
    }
    protected void init(){
        maxInitSize=200*30;
        minInterval=20;
        defaultInterval=DEFAULT_INTERVAL;
    }
    private void reset() {
        initiateIntervals();
        int activeSize = this.calculateActiveSize();
        this.setActiveSize(activeSize );
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
    }
    /*******************************************************************************************************
     *                YAxis locatoin
     *******************************************************************************************************/

    /**
     *  
     *  A better way is to create YAxis name: interval map. It is feasible, but not sure which way is best for users. (e.g. consider moving/swop axis)
     *
     *
     * @return  Y axis' location.x given the display index of the YAxis
     */
    public int getXByIndex(float index) {
        int x=0;
        for (int i=0;i<=index;i++){
            int delx =0;
            if(i<intervals.size())
                 delx = ((Integer)this.intervals.get(i)).intValue();
            else
                 delx= this.getDefaultInterval() ;
            x=x+delx ;
        }
        return(this.getAxisLocation().x+x);
        //return(int) (this.getAxisLocation().x + defaultInterval * index);
    }
    /**
     * Get a YAxis location.x.
     *  
     *  
     *
     * @param axis
     * @return
     */
    public int getLocX(YAxis axis){
        int index = axis.getIndex();
        return getXByIndex(index);
    }

   /*  
    public  void updateYAxisLocX(YAxis axis){
       ...
    }*/
    /*******************************************************************************************************
     *                interaction between Plot.width  and  XAxis.activeSize
     *******************************************************************************************************/
    /**
     * Set number of YAxis that visible
     * @param numOfYAxis   # of YAxis that visible, not necessarily = yaxisList.size() since some YAxis may not visible
     * @return          if true, do update; else mean numOfYAxis is same as before, nothing change
     */
    public boolean setNumOfYAxis(int numOfYAxis) {
      /* this.numOfYAxis = numOfYAxis;
        initiateIntervals();
        this.reset() ; //it will eventually call setActiveSize() = > update plot
        return true;*/

        if(numOfYAxis!=this.numOfYAxis) {// todo ??? why not work
        this.numOfYAxis = numOfYAxis;

        initiateIntervals();// 
        this.reset() ;  //it will eventually call setActiveSize() = > update plot
            return true;
        }
        else{
            return false;
        }
        /*if(numOfYAxis>0)
            this.setDefaultInterval(this.calculateInterval(this.model.activeSize, this.numOfYAxis));*/
    }

    /**
     *  NEVER called from outside, need change interval
     */
    public void setActiveSize(int activeSize) {
        //this.activeSize = activeSize;
        super.setActiveSize(activeSize);
       // this.firePropertyChange(BasicAxis.ActiveSize,"","");  super class will call it
        //this.setDefaultInterval(this.calculateInterval(this.model.activeSize, this.numOfYAxis));  //bug, make interval=145 instead of 150

    }
    //todo:  buggy since now intervals not contain all intervals
    private int calculateActiveSize(){
        int size=0;

        for (int i=0;i<this.getNumOfYAxis();i++){
            size=this.getInterval(i)+size;
        }
        return size;
    }

    /**
     * A proposed the delta size may not realizable since interval must be int.
     * Thus, based on deltaX, we calculate  a feasible interval => activesize
     * @param deltaX    
     * @return   the final new active size of XAxisOrder
     */
    public int proposeChangeActiveSize(int deltaX) {
        Iterator iter=intervals.iterator() ;
        int index=0;
         while(iter.hasNext()){
            float interval = ((Integer)iter.next()).floatValue() ;
            int deltaInterval=Math.round( interval/this.getActiveSize() *deltaX);
            int newInterval= (int) (interval+ deltaInterval);
            this.setIntervalByIndex(index++,newInterval);


         }
         int size=this.calculateActiveSize() ;
         this.setActiveSize(size);
         return size;

    }
   /*******************************************************************************************************
    *                interval
    *******************************************************************************************************/
    /***
     *  
     * @param index
     * @param interval
     */
    public void setIntervalByIndex(int index, int interval) {
       this.intervals.set(index,new Integer(interval));
    }
    /**
     *
     */
    public  void setDefaultInterval(int defaultInterval) {
        int old= this.defaultInterval;
        this.defaultInterval = defaultInterval;
        this.firePropertyChange(PROPERTY_DEFAULT_INTERVAL,old,defaultInterval);

    }
    /**
     * Set all axes' interval as default interval
     * @param defaultInterval
     */
    public  void setAllAsDefaultInterval(int defaultInterval) {
        this.setDefaultInterval(defaultInterval);
        Collections.fill(this.intervals ,new Integer(defaultInterval)) ;
        this.intervals.set(0,new Integer(0));//first element =0;
        int size=this.calculateActiveSize() ;
        this.setActiveSize(size);

    }

    public int getDefaultInterval() {
        return defaultInterval;
    }

    private int calculateInterval(int w, int num) {
        float myw = w;
        return Math.round(myw / this.numOfYAxis);
    }



    public int getInterval(int index) {
        if(index<intervals.size()){
            Integer itv=(Integer)this.intervals.get(index);
            return itv.intValue() ;
        }
        else{
            return this.getDefaultInterval() ;
        }
    }
    /**
     *  Given a location x, return the axis that exactly left to the x
     * @param x
     * @return
     */
    public int findLeftAxis(int x) {
        Object[] itvs=this.intervals.toArray() ;
        int total=this.getLocation().x ;
        if(x<total) return -1;//x is left to the 1st axis
        for (int i=0;i<itvs.length-1 ;i++){
           Integer itv1=(Integer) itvs[i];
           Integer itv2=(Integer) itvs[i+1];
           int it1=itv1.intValue() ;
           int it2=itv2.intValue() ;
           total=total+it1;
           if(total<=x&&x<(total+it2)){
               return i;
           }

        }
        return itvs.length-1;// last axis
    }
    private void initiateIntervals(){
        intervals=new ArrayList(this.numOfYAxis) ;
        intervals.add(new Integer(0));//first axis's interval=0

        int interval=getInitialIntervel(numOfYAxis);
        for (int i=1;i<numOfYAxis;i++){
            this.intervals.add(new Integer(interval)) ;
        }



    }

    private int getInitialIntervel(int numOfAxis){
        int interval=0;
        int defInterval = this.getDefaultInterval();

        if(defInterval*numOfAxis>this.getMaxInitSize()){
            interval=(int) (this.getMaxInitSize()/numOfAxis);
        }
        else
            interval=DEFAULT_INTERVAL;// 

        this.setDefaultInterval(interval);
        return interval;

    }

    public int getMaxInitSize() {
        return maxInitSize;
    }

    public int getMinInterval() {
        return minInterval;
    }
   /* public void setLocation(int x, int y) {
        super.setLocation(x,y);
    }*/
    /*public void setAxisLocation(int x, int y) {
        super.setAxisLocation(x,y);
    }*/
}
